import cv2
import numpy as np
import os
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题

# 读取原图
img = cv2.imread('hanzi1.jpg')

# 1、原图灰度图
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 2、应用全局阈值
_, binary_image = cv2.threshold(gray_image, 110, 255, cv2.THRESH_BINARY_INV)

# 3、定义结构元素
kernel = np.ones((3, 3), np.uint8)
# 应用腐蚀操作
eroded_image = cv2.erode(binary_image, kernel, iterations=3)

# 4、定义结构元素
kernel1 = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5)).astype(np.uint8)
# 应用膨胀操作
dilated_image = cv2.dilate(eroded_image, kernel, iterations=2)
# 中值滤波去除dilated_img的小白点
median_img = cv2.medianBlur(dilated_image, 13)

# 5、定义结构元素
kernel2 = np.ones((7, 7), np.uint8)
# 应用闭运算
closing_image = cv2.morphologyEx(median_img, cv2.MORPH_CROSS, kernel2, iterations=10)

# 6、Canney边缘检测
lower = 50
upper = 200
img_blur = cv2.GaussianBlur(img, (3, 3), 0)  # 高斯滤波
edges_with_blur = cv2.Canny(closing_image, lower, upper)

# 7、识别结果
# 使用Canny边缘检测得到的边缘图像来找到轮廓
contours, _ = cv2.findContours(edges_with_blur, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

# 创建一个全黑的背景图
result_img = np.zeros_like(edges_with_blur)
result = img.copy()

# 遍历轮廓列表
chars_dir = 'chars'  # 字符图像保存目录
count = 1
if not os.path.exists(chars_dir):
    os.makedirs(chars_dir)

for c in contours:
    perimeter = cv2.arcLength(c, True)
    x, y, w, h = cv2.boundingRect(c)
    cv2.rectangle(result_img, (x, y), (x + w, y + h), (255), 2)

    # 根据周长阈值筛选并绘制边界框
    if perimeter > 100:
        cv2.rectangle(result, (x, y), (x + w, y + h), (0, 255, 0), 2)

        # 提取并保存字符图像
        char_img = img[y:y + h, x:x + w]
        char_filename = os.path.join(chars_dir, f'{count}.png')
        cv2.imwrite(char_filename, char_img)
        count += 1

# 可视化展示结果
fig, ax = plt.subplots(1, 7, figsize=(20, 10))
ax[0].imshow(gray_image, cmap='gray')
ax[0].set_title(f"原图灰度图", size=6)
ax[0].axis('off')
ax[1].imshow(binary_image, cmap='gray')
ax[1].set_title(f"进行全局阈值处理，生成二值化图", size=6)
ax[1].axis('off')
ax[2].imshow(eroded_image, cmap='gray')
ax[2].set_title(f"应用腐蚀操作，去除噪点", size=6)
ax[2].axis('off')
ax[3].imshow(dilated_image, cmap='gray')
ax[3].set_title(f"应用膨胀操作，突出图像特征，中值滤波去除小白点", size=6)
ax[3].axis('off')
ax[4].imshow(closing_image, cmap='gray')
ax[4].set_title(f"进行闭运算，填充闭合区域", size=6)
ax[4].axis('off')
ax[5].imshow(edges_with_blur, cmap='gray')
ax[5].set_title(f"Canney边缘检测", size=6)
ax[5].axis('off')
ax[6].imshow(result, cmap='gray')
ax[6].set_title(f"识别结果", size=6)
ax[6].axis('off')

# 调整子图布局
plt.tight_layout()
fig.savefig('visualization.png', dpi=300, bbox_inches='tight')
# 显示图形
plt.show()